// 
// BaseView.ts
// Author:qiuchun(362460803@qq.com)
// Time:2023.05.09 17:55:04
// Desc:View的基类,是组件与mvp的Mediator过渡的类
//
import { _decorator, Component, Node, log, Button, EventHandler, js } from 'cc';
import Mediator from '../lib/mvp/Mediator';
import Notification from '../lib/mvp/Notification';
import Facade from '../lib/mvp/Facade';
import Notifier from '../lib/mvp/Notifier';
import { EDITOR } from 'cc/env';
const { ccclass, executionOrder, executeInEditMode, property } = _decorator;

//组件名,名称缩写的话，节点名称也要跟着对应
const compNames = [
    //单个元素
    "Node",
    "Label",
    "lbl",
    "EditBox",
    "Sprite",
    "spr",
    "Toggle",
    "Button",
    "btn",
    "RichText",
    "ProgressBar",
]

@ccclass('BaseView')
@executeInEditMode(true)
export class BaseView extends Component {

    //事件名称
    static BASEVIEW_INIT = "BASEVIEW_INIT"; //测试用

    //Mediator模型
    private _madiator: Mediator = null;
    public set madiator(madiator: Mediator) {
        this._madiator = madiator;
    }
    public get madiator(): Mediator {
        return this._madiator;
    }

    protected onLoad(): void {
        //框架初始化
        this.init("BaseView");
        //自动绑定
        if (EDITOR) {
            this.bindComponents();
        }
    }

    start() {

    }

    protected onEnable(): void {


        //注册Madiator
        Facade.getInstance().registerMediator(this._madiator);
    }

    protected onDisable(): void {
        //注销Madiator
        if (this._madiator) {
            Facade.getInstance().removeMediator(this._madiator.getName());
        }
    }


    /********************功能函数********************/
    //初始化
    //@param viewName:view在mvp的注册名，用于区别其他view
    init(viewName: string) {
        this._madiator = new Mediator(viewName);
        this._madiator.setHandleNotification(this, this.handleNotification, this.listNotificationInterests);

    }
    //响应函数
    public handleNotification(notification: Notification) {

    }

    //消息队列，注册时会自动绑定
    public listNotificationInterests() {
        let list: Array<string> = [];
        list.push(BaseView.BASEVIEW_INIT);
        return list;
    }

    //发送消息
    //尽量使用已有的封装函数，减少使用单例模式的Facade
    sendNotification(name: string, body?: object, type?: string, dest?: Notifier | string) {
        this._madiator.sendNotification(name, body, type, dest);
    };

    close() {
        this.node.destroy();
    }


    //识别格式：属性名，一下划线开头或者以组件名开头，加关键字，如“_buttonOK”,"_labelName"，“buttonCancel"等；
    //节点名：组件名加关键字，如“Button_OK”,"Label_Name"
    bindComponents() {
        log("绑定开始");
        //遍历属性名
        for (let index in this) {
            if (this[index] == null) {
                //通过组件名来追踪节点
                for (let compIndex in compNames) {
                    let compName = compNames[compIndex];
                    let reg = new RegExp("^_?" + compName, "i");
                    let matchArr = index.match(reg);

                    if (matchArr != null) {

                        let keyName = index.substring(matchArr[0].length);
                        if (keyName && keyName != "") {
                            let node = this.seekNodeByName(this.node, compName, keyName);
                            if (node) {
                                if (compName == "Node") {
                                    this[index] = node as any;
                                    log("属性[" + index + "]" + "绑定节点[" + node.name + "+]成功");
                                }
                                else {
                                    let comp = node.getComponent("cc." + compName);
                                    if (comp) {
                                        this[index] = comp as any;
                                        //如果是按钮组件则自动绑定事件
                                        if (comp instanceof Button) {
                                            let funName = "OnClick_" + keyName;
                                            if (this[funName]) {
                                                let btn = <Button>comp;
                                                if (btn.clickEvents.length == 0) {
                                                    let event = new EventHandler();
                                                    event.target = this.node;
                                                    //自动添加按钮绑定事件，添加组件名没有效果，需要添加组件id才有效果。
                                                    //但是，这是编辑器的环境，在游戏开发里面添加组件名是有效果的。
                                                    // event.component = js.getClassName(this); //无效果
                                                    event._componentId = js.getClassId(this);   //有效果，虽然声明里要被放弃
                                                    event.handler = funName;
                                                    event.customEventData = "代码自动添加";
                                                    btn.clickEvents.push(event);
                                                    log(index + "的按钮事件[" + funName + "]绑定成功。")

                                                }
                                            }

                                        }
                                        log("属性[" + index + "]" + "绑定组件节点[" + node.name + "]成功");
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }
        log("绑定结束");
    }

    //根据格式搜索目标节点，节点名：组件名加关键字，如“Button_OK”,"Label_Name"
    //@param node - 搜寻节点
    //@param compName - 组件名，包括节点名
    //@param keyName - 后缀名，与其他同一类型组件区别出来
    seekNodeByName(node: Node, compName: string, keyName: string): Node {
        let bindName = node.name.split("_");
        if (bindName.length == 2) {
            let compMatch = bindName[0].match(new RegExp(compName, "i"));
            let keyMatch = bindName[1].match(new RegExp(keyName, "i"));


            if (compMatch && keyMatch) {
                return node;
            }
        }

        let children = node.children;
        if (children && children.length > 0) {
            for (let i = 0; i < children.length; i++) {
                let result = this.seekNodeByName(children[i], compName, keyName);
                if (result) {
                    return result;
                }
            }
        }
        return null;
    }

}

